#!/usr/bin/env python

from __future__ import print_function

import getopt
import sys
import os
import base64
import re

# Check if I have all needed dependencies
from w3af.core.controllers.dependency_check.dependency_check import dependency_check
dependency_check()

from w3af.core.ui.console.console_ui import ConsoleUI
from w3af.core.controllers.misc.get_w3af_version import get_w3af_version
import w3af.core.controllers.output_manager as om


# from https://en.wikipedia.org/wiki/Percent-encoding#Types_of_URI_characters
URL_RE = re.compile('^([a-z]|[A-Z]|[0-9]|\.|-|_|~|\[|\]|#|\'|\(|\)|;|:|@|&|=|\+|\$|,|\*|!|\/|\?)+$')


USAGE_DOC = """
w3af - Web Application Attack and Audit Framework

Usage:

    ./w3af_console -h
    ./w3af_console -t
    ./w3af_console [-s <script_file>]

Options:

    -h or --help
        Display this help message

    -s <script_file> or --script=<script_file>
        Run <script_file> script

    -n or --no-update
        No update check will be made when starting. This option takes 
        precedence over the 'auto-update' setting in 'startup.conf' file.
     
    -f or --force-update
        An update check will be made when starting. This option takes 
        precedence over the 'auto-update' setting in 'startup.conf' file.
     
    -p <profile> or --profile=<profile>
        Run with the selected <profile>
    
    -P <profile> or --profile-run=<profile>
        Run with the selected <profile> in batch mode
    
    -v or --version
        Show w3af's version

    -y or --yes
        Automatically agree to disclaimer prompt

    -t or --target
        Target URL for scan

For more info visit http://w3af.org/
"""


def _configure_output_manager():
    """
    Make sure that the output manager is started before doing anything else,
    since it is used by most w3af modules
    """ 
    try:
        om.manager.set_output_plugins(['console'])
    except Exception as e:
        print('Something went wrong, w3af failed to start the output manager.')
        print('Exception: "%s"' % e)
        sys.exit(-9)


def _usage():
    print(USAGE_DOC)


def _generate_run_commands(script_file, profile, force_profile, target_url):
    """
    Given the user configuration, generate the commands to run in the console
    user interface at startup.
    
    :param script_file: The script (-s) file name
    :param profile: The profile (-p) name
    :param force_profile: Should we run the profile? (-P)
    :target_url: Target URL for scan
    """
    commands_to_run = []

    if target_url:
        if URL_RE.match(target_url):
            commands_to_run.extend(['target', 'set target {}'.format(target_url), 'back'])
        else:
            print ('Target URL is invalid')
            sys.exit(2)

    if script_file is not None:
        try:
            fd = open(script_file)
        except IOError:
            print('Failed to open script file: "%s"' % script_file)
            sys.exit(2)
        else:
            for line in fd:   
                line = line.strip()
                # if not a comment..
                if line != '' and line[0] != '#':
                    commands_to_run.append(line)
            fd.close() 
    elif profile is not None:
        
        current_dir = os.getcwd()
        commands_to_run = ["profiles use %s %s" % (profile, current_dir)]
        
        if force_profile is not None:
            commands_to_run.append("start")
            commands_to_run.append("exit")

    return commands_to_run


def main():
    try:
        long_options = ['script=', 'help', 'version', 'no-update',
                        'force-update', 'profile=', 'commit=',
                        'profile-run', 'yes', 'target=']
        opts, _ = getopt.getopt(sys.argv[1:], "ehvs:nfp:P:yt:", long_options)
    except getopt.GetoptError:
        # Print help information and exit
        _usage()
        return -3
    
    script_file = None
    force_profile = None
    profile = None
    do_update = None
    skip_disclaimer = False
    target_url = None
    
    for o, a in opts:
        if o == "-e":
            # easter egg
            msg = 'R3JhY2lhcyBFdWdlIHBvciBiYW5jYXJtZSB0YW50YXMgaG9yYXMgZGUgZG'\
                  'VzYXJyb2xsbywgdGUgYW1vIGdvcmRhIQ=='
            print(base64.b64decode(msg))
        if o in ('-s', '--script'):
            script_file = a
        if o in ('-P', '--profile-run'):
            # selected profile
            force_profile = True
            profile = a
        if o in ('-p', '--profile'):
            # selected profile
            profile = a
        if o in ('-h', '--help'):
            _usage()
            return 0
        if o in ('-v', '--version'):
            print(get_w3af_version())
            return 0
        if o in ('-f', '--force-update'):
            do_update = True
        elif o in ('-n', '--no-update'):
            do_update = False
        if o in ('-y', '--yes'):
            skip_disclaimer = True
        if o in ('-t', '--target'):
            target_url = a
    
    commands_to_run = _generate_run_commands(script_file, profile, force_profile, target_url)
    console = ConsoleUI(commands=commands_to_run, do_upd=do_update)
    
    if not skip_disclaimer and not console.accept_disclaimer():
        return -4

    return console.sh()


def _main():
    _configure_output_manager()
    sys.exit(main())


if __name__ == "__main__":
    _main()
